/********************************************************************************
* @file    bsp_gpio.c
* @author  jianqiang.xue
* @version V1.0.0
* @date    2021-09-30
* @brief   gpio初始化
********************************************************************************/

/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>

#include "RTE_Components.h"
#include CMSIS_device_header

#include "bsp_exti.h"
#include "bsp_gpio.h"

/* Private Includes ----------------------------------------------------------*/
#include "ls_gpio.h"
#include "ls_syscfg.h"

/* Private Variables ---------------------------------------------------------*/
/* Public Function Prototypes ------------------------------------------------*/
/**
 * @brief  [反初始化] 关闭指定引脚功能(恢复为浮空输入)
 * @param  *gpiox: gpio组号（GPIOA/GPIOB/GPIOC/GPIOD等等）
 * @param  pin: 引脚号
 */
void bsp_gpio_deinit(void *gpiox, uint8_t pin)
{
    bsp_gpio_init_input(gpiox, (1 << pin), BSP_GPIO_PIN_NOPULL);
}

/**
 * @brief  [初始化] 引脚设置为输出模式
 * @param  *gpiox: gpio组号（GPIOA/GPIOB/GPIOC/GPIOD等等）
 * @param  pin: 引脚号
 * @param  out_mode:  BSP_GPIO_PIN_OUT_OD 开漏输出, BSP_GPIO_PIN_OUT_PP 推免输出, BSP_GPIO_PIN_AF_OD 复用开漏, BSP_GPIO_PIN_AF_PP 复用推免
 */
void bsp_gpio_init_output(void *gpiox, uint8_t pin, bsp_gpio_pin_out_t out_mode)
{
    volatile GPIO_InitType gpio_init_struct;

    gpio_init_struct.GPIO_Pins            = (1 << pin);
    gpio_init_struct.GPIO_MaxSpeed        = GPIO_MaxSpeed_10MHz;
    if (out_mode == BSP_GPIO_PIN_OUT_OD)
    {
        gpio_init_struct.GPIO_Mode        = GPIO_Mode_OUT_OD;
    }
    else if (out_mode == BSP_GPIO_PIN_OUT_PP)
    {
        gpio_init_struct.GPIO_Mode        = GPIO_Mode_OUT_PP;
    }
    else if (out_mode == BSP_GPIO_PIN_AF_OD)
    {
        gpio_init_struct.GPIO_Mode        = GPIO_Mode_AF_OD;
    }
    else if (out_mode == BSP_GPIO_PIN_AF_PP)
    {
        gpio_init_struct.GPIO_Mode        = GPIO_Mode_AF_PP;
    }
    GPIO_Init(gpiox, (GPIO_InitType *)&gpio_init_struct);
}

/**
 * @brief  [初始化] 引脚设置为输入模式
 * @param  *gpiox: gpio组号（GPIOA/GPIOB/GPIOC/GPIOD等等）
 * @param  pin: 引脚号
 * @param  pull: BSP_GPIO_PIN_NOPULL 无上下拉, BSP_GPIO_PIN_PULLUP 上拉输入, BSP_GPIO_PIN_PULLDOWN 下拉输入
 */
void bsp_gpio_init_input(void *gpiox, uint8_t pin, bsp_gpio_pin_pull_t pull)
{
    volatile GPIO_InitType gpio_init_struct;

    gpio_init_struct.GPIO_Pins            = (1 << pin);
    gpio_init_struct.GPIO_MaxSpeed        = GPIO_MaxSpeed_10MHz;
    if (pull == BSP_GPIO_PIN_NOPULL)
    {
        gpio_init_struct.GPIO_Mode        = GPIO_Mode_IN_FLOATING;
    }
    else if (pull == BSP_GPIO_PIN_PULLUP)
    {
        gpio_init_struct.GPIO_Mode        = GPIO_Mode_IN_PU;
    }
    else if (pull == BSP_GPIO_PIN_PULLDOWN)
    {
        gpio_init_struct.GPIO_Mode        = GPIO_Mode_IN_PD;
    }
    GPIO_Init(gpiox, (GPIO_InitType *)&gpio_init_struct);
}

static uint8_t get_exti_event(bsp_gpio_exti_int_event_t exti_type)
{
    if (BSP_GPIO_EXTI_INT_LOWFALL == exti_type)
    {
        return EXTI_Trigger_Falling;
    }
    else if (BSP_GPIO_EXTI_INT_HIGHRISE == exti_type)
    {
        return EXTI_Trigger_Rising;
    }
    else if (BSP_GPIO_EXTI_INT_FALLRISE == exti_type)
    {
        return EXTI_Trigger_Rising_Falling;
    }
    else
    {
        return EXTI_Trigger_Rising_Falling;
    }
}

/**
 * @brief  [初始化] 引脚设置为[输入+中断]模式
 * @param  *gpiox: gpio组号（GPIOA/GPIOB/GPIOC/GPIOD等等）
 * @param  pin: 引脚号
 * @param  irqn: 中断号（在typedef enum IRQn中，例如：USART1_IRQn）
 * @param  exti_type: BSP_GPIO_EXTI_INT_LEVEL 电平触发, BSP_GPIO_EXTI_INT_EDGE 边沿触发
 * @param  exti_event: BSP_GPIO_EXTI_INT_LOWFALL 低电平触发(下降沿), BSP_GPIO_EXTI_INT_HIGHRISE 高电平触发(上降沿), BSP_GPIO_EXTI_INT_FALLRISE 高低电平触发或任意电平变化
 * @param  pull: BSP_GPIO_PIN_NOPULL 无上下拉, BSP_GPIO_PIN_PULLUP 上拉输入, BSP_GPIO_PIN_PULLDOWN 下拉输入
 */
void bsp_gpio_init_input_exit(void *gpiox, uint8_t pin, uint8_t irqn,
                              bsp_gpio_exti_int_type_t exti_type,
                              bsp_gpio_exti_int_event_t exti_event,
                              bsp_gpio_pin_pull_t pull)
{
    EXTI_InitType EXTI_InitStructure;
    GPIO_Type* GPIOx = gpiox;
    uint8_t PortSource = 0;
    bsp_gpio_init_input(gpiox, (1 << pin), pull);
    //<Connect EXTIx Line to Pxx pin
    if (GPIOx == GPIOA)
    {
        PortSource = GPIO_PortSourceGPIOA;
    }
    else if (GPIOx == GPIOB)
    {
        PortSource = GPIO_PortSourceGPIOB;
    }
    else if (GPIOx == GPIOC)
    {
        PortSource = GPIO_PortSourceGPIOC;
    }
    else if (GPIOx == GPIOD)
    {
        PortSource = GPIO_PortSourceGPIOD;
    }
    GPIO_EXTILineConfig(PortSource, pin);
    /* Configure Button pin as input with External interrupt */
    EXTI_InitStructure.EXTI_Line       = (1 << pin);
    EXTI_InitStructure.EXTI_Mode       = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger    = (EXTITrigger_Type)get_exti_event(exti_event);
    EXTI_InitStructure.EXTI_LineEnable = ENABLE;
    EXTI_Init(&EXTI_InitStructure);

    bsp_exit_clear_flag(gpiox, pin);
    /* Enable and set Button EXTI Interrupt to the lowest priority */
    bsp_exit_set(irqn, pin % 4);
}

/**
 * @brief  设置引脚电平状态
 * @param  *gpiox: gpio组号（GPIOA/GPIOB/GPIOC/GPIOD等等）
 * @param  pin: 引脚号
 * @param  state: BSP_GPIO_PIN_RESET 低电平, BSP_GPIO_PIN_SET 高电平
 */
void bsp_gpio_set_pin(void *gpiox, uint8_t pin, bsp_gpio_pin_state_t state)
{
    GPIO_WriteBit(gpiox, (1 << pin), (BitState)state);
}

/**
 * @brief  翻转引脚电平状态
 * @param  *gpiox: gpio组号（GPIOA/GPIOB/GPIOC/GPIOD等等）
 * @param  pin: 引脚号
 */
void bsp_gpio_set_toggle(void *gpiox, uint8_t pin)
{
    bsp_gpio_set_pin(gpiox, pin, (bsp_gpio_pin_state_t)!bsp_gpio_get_state(gpiox, pin));
}

/**
 * @brief  得到指定gpio状态
 * @param  *gpiox: gpio组号（GPIOA/GPIOB/GPIOC/GPIOD等等）
 * @param  pin: 引脚号
 * @retval 0 -- 低电平, 1 -- 高电平
 */
bool bsp_gpio_get_state(void *gpiox, uint8_t pin)
{
    return (bool)GPIO_ReadInputDataBit(gpiox, (1 << pin));
}

/**
 * @brief  设置gpio时钟
 * @param  aphn: AHB外围x (High Speed APB)外围时钟。APB == 0  APB2 == 1
 * @param  periph: 时钟号
 */
void bsp_gpio_set_clk(bool aphn, uint32_t periph, bool state)
{
    if (aphn == 0)
    {
        RCC_AHBPeriphClockCmd(periph, state);
    }
    else if(aphn == 1)
    {
        RCC_APB2PeriphClockCmd(periph, state);
    }
}

/**
 * @brief  将指定引脚复用为ADC引脚（复用模拟输入）
 * @param  *gpiox: gpio组号（GPIOA/GPIOB/GPIOC/GPIOD等等）
 * @param  pin: 引脚号
 */
void bsp_gpio_init_adc(void *gpiox, uint8_t pin)
{
    GPIO_InitType gpio_init_struct;

    gpio_init_struct.GPIO_Pins            = (1 << pin);
    gpio_init_struct.GPIO_MaxSpeed        = GPIO_MaxSpeed_10MHz;
    gpio_init_struct.GPIO_Mode            = GPIO_Mode_IN_ANALOG;
    GPIO_Init(gpiox, (GPIO_InitType *)&gpio_init_struct);
}

/**
 * @brief  初始化i2c引脚
 * @param  *gpiox: gpio组号（GPIOA/GPIOB/GPIOC/GPIOD等等）
 * @param  pin: 引脚号
 * @param  arf: [复用脚 0--SCL  1--SDA]    (0代表初始化SCL脚，1同理初始化SDA脚)
 */
void bsp_gpio_init_i2c(void *gpiox, uint8_t pin, uint8_t arf)
{
    GPIO_InitType gpio_init_struct;

    gpio_init_struct.GPIO_Pins            = (1 << pin);
    gpio_init_struct.GPIO_MaxSpeed        = GPIO_MaxSpeed_50MHz;
    gpio_init_struct.GPIO_Mode            = GPIO_Mode_AF_OD;
    GPIO_Init(gpiox, (GPIO_InitType *)&gpio_init_struct);
}

/**
 * @brief  初始化uart引脚
 * @param  *gpiox: gpio组号（GPIOA/GPIOB/GPIOC/GPIOD等等）
 * @param  pin: 引脚号
 * @param  arf: [复用脚 0--TX  1--RX]    (0代表初始化TX脚，1同理初始化RX脚)
 */
void bsp_gpio_init_uart(void *gpiox, uint8_t pin, uint8_t arf)
{
    volatile GPIO_InitType gpio_init_struct;
    gpio_init_struct.GPIO_Pins        = (1 << pin);
    gpio_init_struct.GPIO_MaxSpeed    = GPIO_MaxSpeed_50MHz;
    if (arf == 0)
    {
        gpio_init_struct.GPIO_Mode    = GPIO_Mode_AF_PP;
    }
    else
    {
        gpio_init_struct.GPIO_Mode    = GPIO_Mode_IN_FLOATING;
    }
    GPIO_Init(gpiox, (GPIO_InitType *)&gpio_init_struct);
}

void bsp_gpio_init_tim(void *gpiox, uint8_t pin, uint8_t arf)
{
    GPIO_InitType gpio_init_struct;
    gpio_init_struct.GPIO_Pins            = (1 << pin);
    gpio_init_struct.GPIO_MaxSpeed        = GPIO_MaxSpeed_50MHz;
    gpio_init_struct.GPIO_Mode            = GPIO_Mode_AF_PP;
    GPIO_Init(gpiox, (GPIO_InitType *)&gpio_init_struct);
}
